package com.cgs.query.client.config

import com.cgs.query.client.connection.ClientPoolConnectionFactory
import com.cgs.query.client.helper.QueryCenterHelper
import com.cgs.query.client.remote.ClientQueryService
import com.cgs.query.client.remote.RemoteServiceFactory
import com.cgs.query.configuration.ConfigProperties
import com.cgs.query.configuration.QueryConfiguration
import com.cgs.query.connection.ConnectionFactory
import com.cgs.query.executor.Executor
import com.cgs.query.handler.*
import com.cgs.query.handler.executor.JdbcExecutor
import com.cgs.query.handler.render.MultipleParameterHandler
import com.cgs.query.handler.result.MapResultSetHandler
import com.cgs.query.handler.security.DefaultSecurityHandler
import com.cgs.query.service.IQueryService
import com.sucsoft.kotlin.annotation.AllOpen
import mu.KotlinLogging
import org.springframework.beans.factory.annotation.Value
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty
import org.springframework.boot.context.properties.ConfigurationProperties
import org.springframework.context.ApplicationContext
import org.springframework.context.ApplicationContextAware
import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.context.annotation.Import

private val logger = KotlinLogging.logger { }

@AllOpen
@Configuration
@Import(LocalQueryConfiguration::class)
open class ClientConfiguration {

    @Bean
    open fun remotingServiceFactory(remoteHandler: RemoteHandler) =
            RemoteServiceFactory(remoteHandler)

    @Bean
    @ConditionalOnMissingBean(IQueryService::class)
    @ConditionalOnExpression("'\${sql.runner.projectNames:null}' == 'null'")
    open fun defaultRemotingQueryService(remoteServiceFactory: RemoteServiceFactory): IQueryService {
        return remoteServiceFactory.getQueryService().apply { logger.info { "创建RemotingServiceFactory" } }
    }

    @Value("\${sql.runner.projectName:}")
    private var projectName: String = ""

    @Bean
    @ConfigurationProperties(prefix = "sql.runner")
    open fun configProperties(): ConfigProperties = ConfigProperties()

    @Bean
    @ConditionalOnProperty("sql.runner.projectName", matchIfMissing = false)
    open fun defaultQueryCenterHelper(queryService: IQueryService, configProperties: ConfigProperties): QueryCenterHelper {
        return QueryCenterHelper(queryService, projectName, configProperties)
    }

}

@ConditionalOnProperty("sql.runner.projectNames", matchIfMissing = false)
open class LocalQueryConfiguration : ApplicationContextAware {

    @Bean
    @ConditionalOnMissingBean(UserInfoHolder::class)
    open fun defaultUserInfoHolder(): UserInfoHolder {
        return object : UserInfoHolder {
            override fun getUserId(): String = "admin"
        }.apply { logger.info { "生成默认的用户管理,用户id:admin" } }
    }

    @Value("\${sql.runner.projectNames:}")
    private lateinit var projectNames: Array<String>

    @Bean
    @ConditionalOnMissingBean(ResultSetHandler::class)
    open fun defaultResultSetHandler(): ResultSetHandler = MapResultSetHandler().apply { logger.info { "创建MapResultSetHandler" } }

    @Bean
    @ConditionalOnMissingBean(ParameterHandler::class)
    open fun multipleParameterHandler(): ParameterHandler = MultipleParameterHandler().apply { logger.info { "创建MultipleParameterHandler" } }

    @Bean
    @ConditionalOnMissingBean(SecurityHandler::class)
    open fun defaultSecurityHandler(): SecurityHandler = DefaultSecurityHandler().apply { logger.info { "创建DefaultSecurityHandler,不进行操作的权限检查" } }

    @Bean
    @ConditionalOnMissingBean(QueryConfiguration::class)
    open fun defaultConfiguration(configProperties: ConfigProperties, parameterHandler: ParameterHandler, resultSetHandler: ResultSetHandler, securityHandler: SecurityHandler): QueryConfiguration =
            QueryConfiguration(configProperties, parameterHandler, resultSetHandler).apply {
                this.securityHandler = securityHandler
                logger.info { "创建Configuration" }
            }

    @Bean
    open fun clientPoolConnectionFactory(): ClientPoolConnectionFactory =
            ClientPoolConnectionFactory().apply { logger.info { "创建ClientPoolConnectionFactory" } }

    @Bean
    @ConditionalOnMissingBean(Executor::class)
    open fun defaultServerJdbcExecutor(config: QueryConfiguration, connectionFactory: ConnectionFactory): Executor =
            JdbcExecutor(config, connectionFactory).apply { logger.info { "创建ServerJdbcExecutor" } }

    @Bean
    @ConditionalOnMissingBean(IQueryService::class)
    open fun defaultClientQueryService(connectionFactory: ClientPoolConnectionFactory, executor: Executor, remoteServiceFactory: RemoteServiceFactory): IQueryService {
        val remotingQueryService = remoteServiceFactory.getQueryService()
        return ClientQueryService(remotingQueryService, connectionFactory, executor, projectNames).apply { logger.info { "创建ClientQueryService" } }
    }

    @Bean
    @ConditionalOnExpression("'\${sql.runner.projectName:null}' == 'null'")
    open fun defaultQueryCenterHelper(queryService: IQueryService, configProperties: ConfigProperties): QueryCenterHelper {
        return QueryCenterHelper(queryService, projectNames[0], configProperties)
    }

    override fun setApplicationContext(applicationContext: ApplicationContext?) {
        val awareMap = applicationContext!!.getBeansOfType(UserInfoHolderAware::class.java)
        val userInfoHolder = applicationContext.getBean(UserInfoHolder::class.java)
        awareMap.forEach { _, bean -> bean.setUserInfoHolder(userInfoHolder) }
    }
}
